/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

/*
 * DiscoveryPanel.java
 *
 * Created on Dec 10, 2010, 5:14:03 PM
 */
package com.bff.slimserver.musicjukebox.ui.settings;

import com.bff.bjj.ui.component.BJJButton;
import com.bff.bjj.ui.component.BJJLabel;
import com.bff.bjj.ui.component.BJJPanel;
import java.awt.Component;
import java.io.IOException;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.ListCellRenderer;
import org.bff.slimserver.SlimDiscoverer;

/**
 *
 * @author Bill
 */
public class DiscoveryPanel extends BJJPanel {

    private DefaultComboBoxModel serverModel;
    private boolean searching;
    private Searcher searcher;

    /** Creates new form DiscoveryPanel */
    public DiscoveryPanel() {
        serverModel = new DefaultComboBoxModel();
        searcher = new Searcher();
        initComponents();
        cbServers.setRenderer(new ServerRenderer());
        searchBar.setVisible(false);
        jLabel1.setVisible(false);
    }

    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {
        java.awt.GridBagConstraints gridBagConstraints;

        jPanel1 = new BJJPanel();
        jPanel3 = new BJJPanel();
        cbServers = new javax.swing.JComboBox();
        lblFound = new BJJLabel();
        jPanel4 = new BJJPanel();
        searchBar = new javax.swing.JProgressBar();
        jLabel1 = new BJJLabel();
        jPanel2 = new BJJPanel();
        btnStop = new BJJButton();

        setLayout(new java.awt.BorderLayout());

        jPanel1.setLayout(new java.awt.BorderLayout());

        jPanel3.setLayout(new java.awt.GridBagLayout());

        cbServers.setModel(serverModel);
        cbServers.setMinimumSize(new java.awt.Dimension(400, 25));
        cbServers.setPreferredSize(new java.awt.Dimension(400, 25));
        jPanel3.add(cbServers, new java.awt.GridBagConstraints());

        lblFound.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
        lblFound.setText(" ");
        lblFound.setOpaque(true);
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 1;
        gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
        jPanel3.add(lblFound, gridBagConstraints);

        jPanel1.add(jPanel3, java.awt.BorderLayout.CENTER);

        jPanel4.setLayout(new java.awt.BorderLayout());

        searchBar.setIndeterminate(true);
        jPanel4.add(searchBar, java.awt.BorderLayout.SOUTH);

        jLabel1.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
        jLabel1.setText("Searching for SqueezeBox Servers...this can take a few seconds");
        jLabel1.setOpaque(true);
        jPanel4.add(jLabel1, java.awt.BorderLayout.CENTER);
        jLabel1.getAccessibleContext().setAccessibleName("Searching for SqueezeBox Servers...this can take a few seconds");

        jPanel1.add(jPanel4, java.awt.BorderLayout.SOUTH);

        add(jPanel1, java.awt.BorderLayout.CENTER);

        btnStop.setText("Start Search");
        btnStop.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                btnStopActionPerformed(evt);
            }
        });
        jPanel2.add(btnStop);

        add(jPanel2, java.awt.BorderLayout.SOUTH);
    }// </editor-fold>//GEN-END:initComponents

    private void btnStopActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnStopActionPerformed
        if (isSearching()) {
            stopSearch();
        } else {
            startSearch();
        }
    }//GEN-LAST:event_btnStopActionPerformed
    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JButton btnStop;
    private javax.swing.JComboBox cbServers;
    private javax.swing.JLabel jLabel1;
    private javax.swing.JPanel jPanel1;
    private javax.swing.JPanel jPanel2;
    private javax.swing.JPanel jPanel3;
    private javax.swing.JPanel jPanel4;
    private javax.swing.JLabel lblFound;
    private javax.swing.JProgressBar searchBar;
    // End of variables declaration//GEN-END:variables

    public InetAddress getSelectedServer() {
        return (InetAddress) serverModel.getSelectedItem();
    }

    public void startSearch() {
        serverModel = new DefaultComboBoxModel();
        cbServers.setModel(serverModel);
        setSearching(true);
        btnStop.setText("Stop Search");
        jLabel1.setVisible(true);
        searchBar.setVisible(true);
        lblFound.setText(" ");
        new Thread(searcher).start();
    }

    public void stopSearch() {
        setSearching(false);
        searcher.setStopped(true);
        searchBar.setVisible(true);
        jLabel1.setVisible(false);
        searchBar.setVisible(false);
        btnStop.setText("Start Search");
    }

    /**
     * @return the searching
     */
    public boolean isSearching() {
        return searching;
    }

    /**
     * @param searching the searching to set
     */
    public void setSearching(boolean searching) {
        this.searching = searching;
    }

    private void serversFound() {
        serverModel = new DefaultComboBoxModel();
        List<InetAddress> servers = serverList;
        for (InetAddress s : servers) {
            serverModel.addElement(s);
        }
        cbServers.setModel(serverModel);
        lblFound.setText("Found " + servers.size() + " server(s)");
    }

    private List<InetAddress> serverList;


    private class Searcher implements Runnable {

        private boolean stopped;
        private SlimDiscoverer discoverer;
        
        public Searcher() {
            discoverer = new SlimDiscoverer();
            serverList = new ArrayList<InetAddress>();
        }

        @Override
        public void run() {
            try {
                discoverer.startDiscovery();
            } catch (SocketException ex) {
                Logger.getLogger(DiscoveryPanel.class.getName()).log(Level.SEVERE, null, ex);
            } catch (UnknownHostException ex) {
                Logger.getLogger(DiscoveryPanel.class.getName()).log(Level.SEVERE, null, ex);
            } catch (IOException ex) {
                Logger.getLogger(DiscoveryPanel.class.getName()).log(Level.SEVERE, null, ex);
            }
            int foundSize = 0;
            while (!isStopped()) {
                if (discoverer.getDiscoveredServers().size() > foundSize) {
                    Set<String> ss = discoverer.getDiscoveredServers().keySet();
                    for (String s : ss) {
                        InetAddress server = discoverer.getDiscoveredServers().get(s);
                        if (!serverList.contains(server)) {
                            serverList.add(server);
                        }
                    }
                    foundSize = discoverer.getDiscoveredServers().size();
                    serversFound();
                }
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException ex) {
                    Logger.getLogger(DiscoveryPanel.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
            discoverer.stopDiscovery();
        }

        /**
         * @return the stopped
         */
        public boolean isStopped() {
            return stopped;
        }

        /**
         * @param stopped the stopped to set
         */
        public void setStopped(boolean stopped) {
            this.stopped = stopped;
        }
    }

    private class ServerRenderer extends JLabel implements ListCellRenderer {

        public ServerRenderer() {
            super();
        }
        
        @Override
        public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
            if(value == null) {
                return this;
            }
            
            if(value instanceof InetAddress) {
                InetAddress address = (InetAddress)value;
                setText(address.getHostName() + " (" + address.getHostAddress() + ")");

            } else {
                setText(value.toString());
            }

            return this;
        }

    }
}
